home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 7: Sunsite / Linux Cubed Series 7 - Sunsite Vol 1.iso / system / shells / rc-1.000 / rc-1 / rc-1.5-linux / glom.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-03-07  |  8.9 KB  |  427 lines

  1. /* glom.c: builds an argument list out of words, variables, etc. */
  2.  
  3. #include <sys/types.h>
  4. #include <sys/stat.h>
  5. #include <signal.h>
  6. #include <errno.h>
  7. #include "rc.h"
  8. #if !defined(S_IFIFO) && !defined(DEVFD)
  9. #define NOCMDARG
  10. #endif
  11.  
  12. static List *backq(Node *, Node *);
  13. static List *bqinput(List *, int);
  14. static List *count(List *);
  15. static List *mkcmdarg(Node *);
  16.  
  17. Rq *redirq = NULL;
  18.  
  19. extern List *word(char *w, char *m) {
  20.     List *s = NULL;
  21.     if (w != NULL) {
  22.         s = nnew(List);
  23.         s->w = w;
  24.         s->m = m;
  25.         s->n = NULL;
  26.     }
  27.     return s;
  28. }
  29.  
  30. /*
  31.    Append list s2 to list s1 by copying s1 and making the new copy
  32.    point at s2.
  33. */
  34.  
  35. extern List *append(List *s1, List *s2) {
  36.     List *r, *top;
  37.     if (s1 == NULL)
  38.         return s2;
  39.     if (s2 == NULL)
  40.         return s1;
  41.     for (r = top = nnew(List); 1; r = r->n = nnew(List)) {
  42.         r->w = s1->w;
  43.         r->m = s1->m;
  44.         if ((s1 = s1->n) == NULL)
  45.             break;
  46.     }
  47.     r->n = s2;
  48.     return top;
  49. }
  50.  
  51. extern List *concat(List *s1, List *s2) {
  52.     int n1, n2;
  53.     List *r, *top;
  54.     if (s1 == NULL)
  55.         return s2;
  56.     if (s2 == NULL)
  57.         return s1;
  58.     if ((n1 = listnel(s1)) != (n2 = listnel(s2)) && n1 != 1 && n2 != 1)
  59.         rc_error("bad concatenation");
  60.     for (r = top = nnew(List); 1; r = r->n = nnew(List)) {
  61.         SIZE_T x = strlen(s1->w);
  62.         SIZE_T y = strlen(s2->w);
  63.         SIZE_T z = x + y + 1;
  64.         r->w = nalloc(z);
  65.         strcpy(r->w, s1->w);
  66.         strcat(r->w, s2->w);
  67.         if (s1->m == NULL && s2->m == NULL) {
  68.             r->m = NULL;
  69.         } else {
  70.             r->m = nalloc(z);
  71.             if (s1->m == NULL)
  72.                 memzero(r->m, x);
  73.             else
  74.                 memcpy(r->m, s1->m, x);
  75.             if (s2->m == NULL)
  76.                 memzero(&r->m[x], y);
  77.             else
  78.                 memcpy(&r->m[x], s2->m, y);
  79.             r->m[z] = 0;
  80.         }
  81.         if (n1 > 1)
  82.             s1 = s1->n;
  83.         if (n2 > 1)
  84.             s2 = s2->n;
  85.         if (s1 == NULL || s2 == NULL || (n1 == 1 && n2 == 1))
  86.             break;
  87.     }
  88.     r->n = NULL;
  89.     return top;
  90. }
  91.  
  92. extern List *varsub(List *var, List *subs) {
  93.     List *r, *top;
  94.     int n = listnel(var);
  95.     for (top = r = NULL; subs != NULL; subs = subs->n) {
  96.         int i = a2u(subs->w);
  97.         if (i < 1)
  98.             rc_error("bad subscript");
  99.         if (i <= n) {
  100.             List *sub = var;
  101.             while (--i)
  102.                 sub = sub->n; /* loop until sub == var(i) */
  103.             if (top == NULL)
  104.                 top = r = nnew(List);
  105.             else
  106.                 r = r->n = nnew(List);
  107.             r->w = sub->w;
  108.             r->m = sub->m;
  109.         }
  110.     }
  111.     if (top != NULL)
  112.         r->n = NULL;
  113.     return top;
  114. }
  115.  
  116. extern List *flatten(List *s) {
  117.     List *r;
  118.     SIZE_T step;
  119.     char *f;
  120.     if (s == NULL || s->n == NULL)
  121.         return s;
  122.     r = nnew(List);
  123.     f = r->w = nalloc(listlen(s) + 1);
  124.     r->m = NULL; /* flattened lists come from variables, so no meta */
  125.     r->n = NULL;
  126.     strcpy(f, s->w);
  127.     f += strlen(s->w);
  128.     do {
  129.         *f++ = ' ';
  130.         s = s->n;
  131.         step = strlen(s->w);
  132.         memcpy(f, s->w, step);
  133.         f += step;
  134.     } while (s->n != NULL);
  135.     *f = '\0';
  136.     return r;
  137. }
  138.  
  139. static List *count(List *l) {
  140.     List *s = nnew(List);
  141.     s->w = nprint("%d", listnel(l));
  142.     s->n = NULL;
  143.     s->m = NULL;
  144.     return s;
  145. }
  146.  
  147. extern void assign(List *s1, List *s2, bool stack) {
  148.     List *val = s2;
  149.     if (s1 == NULL)
  150.         rc_error("null variable name");
  151.     if (s1->n != NULL)
  152.         rc_error("multi-word variable name");
  153.     if (*s1->w == '\0')
  154.         rc_error("zero-length variable name");
  155.     if (a2u(s1->w) != -1)
  156.         rc_error("numeric variable name");
  157.     if (strchr(s1->w, '=') != NULL)
  158.         rc_error("'=' in variable name");
  159.     if (*s1->w == '*' && s1->w[1] == '\0')
  160.         val = append(varlookup("0"), s2); /* preserve $0 when * is assigned explicitly */
  161.     if (s2 != NULL || stack) {
  162.         if (dashex)
  163.             prettyprint_var(2, s1->w, val);
  164.         varassign(s1->w, val, stack);
  165.         alias(s1->w, varlookup(s1->w), stack);
  166.     } else {
  167.         if (dashex)
  168.             prettyprint_var(2, s1->w, NULL);
  169.         varrm(s1->w, stack);
  170.     }
  171. }
  172.  
  173. /*
  174.    The following two functions are by the courtesy of Paul Haahr,
  175.    who could not stand the incompetence of my own backquote implementation.
  176. */
  177.  
  178. #define BUFSIZE    ((SIZE_T) 1000)
  179.  
  180. static List *bqinput(List *ifs, int fd) {
  181.     char *end, *bufend, *s;
  182.     List *r, *top, *prev;
  183.     SIZE_T remain, bufsize;
  184.     char isifs[256];
  185.     int n, state; /* a simple FSA is used to read in data */
  186.  
  187.     memzero(isifs, sizeof isifs);
  188.     for (isifs['\0'] = TRUE; ifs != NULL; ifs = ifs->n)
  189.         for (s = ifs->w; *s != '\0'; s++)
  190.             isifs[*(unsigned char *)s] = TRUE;
  191.     remain = bufsize = BUFSIZE;
  192.     top = r = nnew(List);
  193.     r->w = end = nalloc(bufsize + 1);
  194.     r->m = NULL;
  195.     state = 0;
  196.     prev = NULL;
  197.  
  198.     while (1) {
  199.         if (remain == 0) { /* is the string bigger than the buffer? */
  200.             SIZE_T m = end - r->w;
  201.             char *buf;
  202.             while (bufsize < m + BUFSIZE)
  203.                 bufsize *= 2;
  204.             buf = nalloc(bufsize + 1);
  205.             memcpy(buf, r->w, m);
  206.             r->w = buf;
  207.             end = &buf[m];
  208.             remain = bufsize - m;
  209.         }
  210.         if ((n = rc_read(fd, end, remain)) <= 0) {
  211.             if (n == 0)
  212.     /* break */        break;
  213.             else if (errno == EINTR)
  214.                 return NULL; /* interrupted, wait for subproc */
  215.             else {
  216.                 uerror("backquote read");
  217.                 rc_error(NULL);
  218.             }
  219.         }
  220.         remain -= n;
  221.         for (bufend = &end[n]; end < bufend; end++)
  222.             if (state == 0) {
  223.                 if (!isifs[*(unsigned char *)end]) {
  224.                     state = 1;
  225.                     r->w = end;
  226.                     r->m = NULL;
  227.                 }
  228.             } else {
  229.                 if (isifs[*(unsigned char *)end]) {
  230.                     state = 0;
  231.                     *end = '\0';
  232.                     prev = r;
  233.                     r = r->n = nnew(List);
  234.                     r->w = end+1;
  235.                     r->m = NULL;
  236.                 }
  237.             }
  238.     }
  239.     if (state == 1) { /* terminate last string */
  240.         *end = '\0';
  241.         r->n = NULL;
  242.     } else {
  243.         if (prev == NULL) /* no input at all? */
  244.             top = NULL;
  245.         else
  246.             prev->n = NULL; /* else terminate list */
  247.     }
  248.     return top;
  249. }
  250.  
  251. static List *backq(Node *ifs, Node *n) {
  252.     int p[2], pid, sp;
  253.     List *bq;
  254.     if (n == NULL)
  255.         return NULL;
  256.     if (pipe(p) < 0) {
  257.         uerror("pipe");
  258.         rc_error(NULL);
  259.     }
  260.     if ((pid = rc_fork()) == 0) {
  261.         mvfd(p[1], 1);
  262.         close(p[0]);
  263.         redirq = NULL;
  264.         walk(n, FALSE);
  265.         exit(getstatus());
  266.     }
  267.     close(p[1]);
  268.     bq = bqinput(glom(ifs), p[0]);
  269.     close(p[0]);
  270.     rc_wait4(pid, &sp, TRUE);
  271.     statprint(-1, sp);
  272.     varassign("bqstatus", word(strstatus(sp), NULL), FALSE);
  273.     sigchk();
  274.     return bq;
  275. }
  276.  
  277. extern void qredir(Node *n) {
  278.     Rq *next;
  279.     if (redirq == NULL) {
  280.         next = redirq = nnew(Rq);
  281.     } else {
  282.         for (next = redirq; next->n != NULL; next = next->n)
  283.             ;
  284.         next->n = nnew(Rq);
  285.         next = next->n;
  286.     }
  287.     next->r = n;
  288.     next->n = NULL;
  289. }
  290.  
  291. #ifdef NOCMDARG
  292. static List *mkcmdarg(Node *n) {
  293.     rc_error("named pipes are not supported");
  294.     return NULL;
  295. }
  296. #else
  297. #ifndef DEVFD
  298. static List *mkcmdarg(Node *n) {
  299.     int fd;
  300.     char *name;
  301.     Edata efifo;
  302.     Estack *e = enew(Estack);
  303.     List *ret = nnew(List);
  304.     static int fifonumber = 0;
  305.     name = nprint("%s/rc%d.%d", TMPDIR, getpid(), fifonumber++);
  306.     if (mknod(name, S_IFIFO | 0666, 0) < 0) {
  307.         uerror("mknod");
  308.         return NULL;
  309.     }
  310.     if (rc_fork() == 0) {
  311.         setsigdefaults(FALSE);
  312.         fd = rc_open(name, (n->u[0].i != rFrom) ? rFrom : rCreate); /* stupid hack */
  313.         if (fd < 0) {
  314.             uerror("open");
  315.             exit(1);
  316.         }
  317.         if (mvfd(fd, (n->u[0].i == rFrom)) < 0) /* same stupid hack */
  318.             exit(1);
  319.         redirq = NULL;
  320.         walk(n->u[2].p, FALSE);
  321.         exit(getstatus());
  322.     }
  323.     efifo.name = name;
  324.     except(eFifo, efifo, e);
  325.     ret->w = name;
  326.     ret->m = NULL;
  327.     ret->n = NULL;
  328.     return ret;
  329. }
  330. #else
  331. static List *mkcmdarg(Node *n) {
  332.     char *name;
  333.     List *ret = nnew(List);
  334.     Estack *e = nnew(Estack);
  335.     Edata efd;
  336.     int p[2];
  337.     if (pipe(p) < 0) {
  338.         uerror("pipe");
  339.         return NULL;
  340.     }
  341.     if (rc_fork() == 0) {
  342.         setsigdefaults(FALSE);
  343.         if (mvfd(p[n->u[0].i == rFrom], n->u[0].i == rFrom) < 0) /* stupid hack */
  344.             exit(1);
  345.         close(p[n->u[0].i != rFrom]);
  346.         redirq = NULL;
  347.         walk(n->u[2].p, FALSE);
  348.         exit(getstatus());
  349.     }
  350.     name = nprint("/dev/fd/%d", p[n->u[0].i != rFrom]);
  351.     efd.fd = p[n->u[0].i != rFrom];
  352.     except(eFd, efd, e);
  353.     close(p[n->u[0].i == rFrom]);
  354.     ret->w = name;
  355.     ret->m = NULL;
  356.     ret->n = NULL;
  357.     return ret;
  358. }
  359. #endif /* DEVFD */
  360. #endif /* !NOCMDARG */
  361.  
  362. extern List *glom(Node *n) {
  363.     List *v, *head, *tail;
  364.     Node *words;
  365.     if (n == NULL)
  366.         return NULL;
  367.     switch (n->type) {
  368.     case nArgs:
  369.     case nLappend:
  370.         words = n->u[0].p;
  371.         tail = NULL;
  372.         while (words != NULL && (words->type == nArgs || words->type == nLappend)) {
  373.             if (words->u[1].p != NULL && words->u[1].p->type != nWord && words->u[1].p->type != nQword)
  374.                 break;
  375.             head = glom(words->u[1].p);
  376.             if (head != NULL) {
  377.                 head->n = tail;
  378.                 tail = head;
  379.             }
  380.             words = words->u[0].p;
  381.         }
  382.         v = append(glom(words), tail); /* force left to right evaluation */
  383.         return append(v, glom(n->u[1].p));
  384.     case nBackq:
  385.         return backq(n->u[0].p, n->u[1].p);
  386.     case nConcat:
  387.         head = glom(n->u[0].p); /* force left-to-right evaluation */
  388.         return concat(head, glom(n->u[1].p));
  389.     case nDup:
  390.     case nRedir:
  391.         qredir(n);
  392.         return NULL;
  393.     case nWord:
  394.     case nQword:
  395.         return word(n->u[0].s, n->u[1].s);
  396.     case nNmpipe:
  397.         return mkcmdarg(n);
  398.     default:
  399.         /*
  400.            The next four operations depend on the left-child of glom
  401.            to be a variable name. Therefore the variable is looked up
  402.            here.
  403.         */
  404.         if ((v = glom(n->u[0].p)) == NULL)
  405.             rc_error("null variable name");
  406.         if (v->n != NULL)
  407.             rc_error("multi-word variable name");
  408.         if (*v->w == '\0')
  409.             rc_error("zero-length variable name");
  410.         v = (*v->w == '*' && v->w[1] == '\0') ? varlookup(v->w)->n : varlookup(v->w);
  411.         switch (n->type) {
  412.         default:
  413.             panic("unexpected node in glom");
  414.             exit(1);
  415.             /* NOTREACHED */
  416.         case nCount:
  417.             return count(v);
  418.         case nFlat:
  419.             return flatten(v);
  420.         case nVar:
  421.             return v;
  422.         case nVarsub:
  423.             return varsub(v, glom(n->u[1].p));
  424.         }
  425.     }
  426. }
  427.